package com.bcx.wind.workflow.core.flow.handler;

import com.bcx.wind.workflow.core.constant.WorkflowOperate;
import com.bcx.wind.workflow.errorcontext.WindError;
import com.bcx.wind.workflow.interceptor.CommandContext;
import com.bcx.wind.workflow.pojo.*;
import com.bcx.wind.workflow.support.JsonHelper;
import com.bcx.wind.workflow.support.ObjectHelper;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.bcx.wind.workflow.core.constant.Constant.ONE;
import static com.bcx.wind.workflow.core.constant.Constant.ZERO;
import static com.bcx.wind.workflow.core.constant.NodeConfigConstant.JOINTLY_APPROVE_TIME_SET;
import static com.bcx.wind.workflow.core.constant.NodeConfigConstant.JOINTLY_APPROVE_USER_MIN_COUNT;
import static com.bcx.wind.workflow.core.constant.NodeConfigConstant.JOINTLY_APPROVE_USER_SET;
import static com.bcx.wind.workflow.core.constant.OrderVariableConstant.*;
import static com.bcx.wind.workflow.core.constant.OrderVariableConstant.JOINTLY_MIN_COUNT;
import static com.bcx.wind.workflow.message.ErrorCode.NODE_CONFIG_ERROR;

/**
 * @author zhanglei
 */
public abstract class BaseExecuteHandler implements ExecuteHandler {

    /**
     * 执行数据
     */
    protected CommandContext commandContext;

    /**
     * 当前任务
     */
    protected Task task;

    public BaseExecuteHandler(CommandContext commandContext,Task task){
        this.commandContext = commandContext;
        this.task = task;
    }

    /**
     * 执行
     */
    public abstract void commandExecute();

    /**
     * 所有需要审批的任务数量
     */
    public abstract  int  allTaskCount();

    @Override
    public void execute() {
        commandExecute();
    }


    Object  getOrderValue(String key){
        Map<String,Object> variable = this.wind().getWindOrder().variable();
        return  variable.get(key);
    }

    protected Wind wind(){
        return this.commandContext.getWind();
    }

    /**
     * 根据键，获取指定节点配置
     * @param key  键
     * @return   节点配置值
     */
    private String getConfigValue(String key){
        WindConfig config =  this.task.getConfig();
        if(config != null){
            Map<String,Object> nodeConfig = config.nodeConfig();
            Object value = nodeConfig.get(key);
            return value == null ? null : value.toString();
        }
        return null;
    }

    /**
     * 当前节点是否合并会签审批人
     *
     * @return  是否合并会签审批人
     */
    private boolean mergeApproveUser(){
        Object merge = getConfigValue(JOINTLY_APPROVE_USER_SET);
        if(merge == null){
            return false;
        }

        try {
            int m = Integer.parseInt(merge.toString());
            return m == 1;
        }catch (Exception e){
            WindError.error(NODE_CONFIG_ERROR,e,wind().getWindProcess().getProcessName(),
                    this.task.getNodeId(),JOINTLY_APPROVE_USER_SET);
        }
        return false;
    }


    /**
     * 合并审批人
     */
    @SuppressWarnings("unchecked")
    void  mergeUser(){
        //审批人合并
        if(WorkflowOperate.submit==this.wind().getOperate() && mergeApproveUser()) {
            Object mergeUser = getOrderValue(APPROVE_USER_MERGE);
            List<ApproveUser> approveUsers = this.wind().getApproveUsers();
            if (!ObjectHelper.isEmpty(approveUsers)) {
                if (mergeUser == null) {
                    Map<String, Object> nowNodeUser = new HashMap<>(4);
                    Map<String, List<WindUser>> userMap = merge(approveUsers);
                    nowNodeUser.put(this.task.getNodeId(), userMap);
                    this.wind().getWindOrder().addVariable(APPROVE_USER_MERGE, nowNodeUser);
                } else{
                    Map<String,Object> nodeMerge = JsonHelper.objectToMap(mergeUser);
                    Object nodeMergeVar = nodeMerge.get(this.task.getNodeId());
                    if(nodeMergeVar == null){
                        Map<String, List<WindUser>> userMap = merge(approveUsers);
                        nodeMerge.put(this.task.getNodeId(),userMap);
                        this.wind().getWindOrder().addVariable(APPROVE_USER_MERGE,nodeMerge);
                    }else{
                        Map<String,Object> nodeMergeUserVar = JsonHelper.objectToMap(nodeMergeVar);
                        for(ApproveUser approveUser : approveUsers){
                            String nodeId = approveUser.getNodeId();
                            List<WindUser>  users = approveUser.getUsers();
                            Object var = nodeMergeUserVar.get(nodeId);
                            if(var != null){
                                List<WindUser> windUsers = JsonHelper.coverObject(var,List.class,WindUser.class);
                                for(WindUser user : users){
                                    if(!windUsers.contains(user)){
                                        windUsers.add(user);
                                    }
                                }
                                nodeMergeUserVar.put(nodeId,windUsers);
                            }
                        }
                        nodeMerge.put(this.task.getNodeId(),nodeMergeUserVar);
                        this.wind().getWindOrder().addVariable(APPROVE_USER_MERGE,nodeMerge);
                    }
                }
            }
        }
    }


    private Map<String,List<WindUser>>  merge(List<ApproveUser> approveUsers){
        Map<String, List<WindUser>> userMap = new HashMap<>(4);
        merge(approveUsers,userMap);
        return userMap;
    }


    private void  merge(List<ApproveUser> approveUsers ,Map<String,List<WindUser>> userVar){
        for (ApproveUser user : approveUsers) {
            String nodeId = user.getNodeId();
            List<WindUser> users = user.getUsers();
            userVar.put(nodeId, users);
        }
    }


    /**
     * 添加会签任务需要完成的最少提交数量
     */
    void  addTaskApproveCount(){
        Object jointlyMin = getOrderValue(JOINTLY_MIN_COUNT);
        //如果不存在会签变量，则新增
        if(jointlyMin == null){
            Map<String,Object> jointlyMinObj = new HashMap<>(4);
            Map<String,Object> jointlyMinNode = new HashMap<>(4);
            jointlyMinNode.put(JOINTLY_SUCCESS_COUNT,Integer.toString(getMinApproveCount(allTaskCount())));
            jointlyMinNode.put(JOINTLY_NOW_COUNT,WorkflowOperate.submit==this.wind().getOperate() ? ONE : ZERO);
            jointlyMinObj.put(this.task.getNodeId(),jointlyMinNode);
            this.wind().getWindOrder().addVariable(JOINTLY_MIN_COUNT,jointlyMinObj);
        }else{
            Map<String,Object> jointlyMinObj = JsonHelper.objectToMap(jointlyMin);
            Object nodeJointly = jointlyMinObj.get(this.task.getNodeId());

            //如果不存在节点会签变量，则新增
            if(nodeJointly == null){
                Map<String,Object> jointlyMinNode = new HashMap<>(4);
                jointlyMinNode.put(JOINTLY_SUCCESS_COUNT,Integer.toString(getMinApproveCount(allTaskCount())));
                jointlyMinNode.put(JOINTLY_NOW_COUNT,WorkflowOperate.submit==this.wind().getOperate() ? ONE : ZERO);
                jointlyMinObj.put(this.task.getNodeId(),jointlyMinNode);
                this.wind().getWindOrder().addVariable(JOINTLY_MIN_COUNT,jointlyMinObj);
            }else{
                //将审批人+1
                Map<String,Object> jointlyMinMap = JsonHelper.objectToMap(nodeJointly);
                Object minCount = jointlyMinMap.get(JOINTLY_NOW_COUNT);
                if(minCount != null){
                    int min = Integer.parseInt(minCount.toString());
                    min = WorkflowOperate.submit==this.wind().getOperate() ? min+1 : min;
                    jointlyMinMap.put(JOINTLY_NOW_COUNT,Integer.toString(min));
                }
                jointlyMinObj.put(this.task.getNodeId(),jointlyMinMap);
                this.wind().getWindOrder().addVariable(JOINTLY_MIN_COUNT,jointlyMinObj);
            }

        }
    }





    /**
     * 会签情况下从配置中获取最小审批数量
     * @param allTaskCount  所有需要审批的任务数量
     *
     * @return 最小审批数量
     */
    private int  getMinApproveCount(int allTaskCount){
        String approveTimeSet = getConfigValue(JOINTLY_APPROVE_TIME_SET);
        String approveMinCount = getConfigValue(JOINTLY_APPROVE_USER_MIN_COUNT);
        if (approveTimeSet != null) {
            Float flo = 0f;
            try {
                flo = Float.parseFloat(approveTimeSet);
            } catch (Exception e) {
                WindError.error(NODE_CONFIG_ERROR, null, this.wind().getWindProcess().getProcessName(),
                        this.task.getNodeId(), JOINTLY_APPROVE_TIME_SET);
            }
            if(flo > 1){
                flo = 1f;
            }
            int min = (int) (allTaskCount * flo);
            return min <= 0 ? 1 : min;
        }
        try {
            if(approveMinCount != null) {
                return Integer.parseInt(approveMinCount);
            }
        } catch (Exception e) {
            WindError.error(NODE_CONFIG_ERROR, null, this.wind().getWindProcess().getProcessName(),
                    this.task.getNodeId(), JOINTLY_APPROVE_TIME_SET);
        }
        return allTaskCount;
    }

}
